package com.gxc.array;

import java.util.Arrays;

/**
 * 31. 下一个排列
 * 整数数组的一个 排列  就是将其所有成员以序列或线性顺序排列。
 *
 * 例如，arr = [1,2,3] ，以下这些都可以视作 arr 的排列：[1,2,3]、[1,3,2]、[3,1,2]、[2,3,1] 。
 * 整数数组的 下一个排列 是指其整数的下一个字典序更大的排列。
 * 更正式地，如果数组的所有排列根据其字典顺序从小到大排列在一个容器中，那么数组的
 * 下一个排列 就是在这个有序容器中排在它后面的那个排列。如果不存在下一个更大的排列，
 * 那么这个数组必须重排为字典序最小的排列（即，其元素按升序排列）。
 *
 * 例如，arr = [1,2,3] 的下一个排列是 [1,3,2] 。
 * 类似地，arr = [2,3,1] 的下一个排列是 [3,1,2] 。
 * 而 arr = [3,2,1] 的下一个排列是 [1,2,3] ，因为 [3,2,1] 不存在一个字典序更大的排列。
 * 给你一个整数数组 nums ，找出 nums 的下一个排列。
 *
 * 必须 原地 修改，只允许使用额外常数空间。
 */
public class NextPermutation {
    public static void main(String[] args) {
        nextPermutation(new int[]{1, 5, 1});
    }

    public static void main2(String[] args) {
        int[] num = new int[]{2,1,3};
        handle(num);
        printArr(num);

        num = new int[]{1, 2};
        handle(num);
        printArr(num);

        num = new int[]{4,2,0,2,3,2,0};
        handle(num);
        printArr(num);
    }

    /**
     * 思路：
     * 从后向前 查找第一个 相邻升序 的元素对 (i,j)，满足 A[i] < A[j]。此时 [j,end) 必然是降序
     * 在 [j,end) 从后向前 查找第一个满足 A[i] < A[k] 的 k。
     * A[i]、A[k] 分别就是上文所说的「小数」、「大数」
     * 将 A[i] 与 A[k] 交换
     * 可以断定这时 [j,end) 必然是降序，逆置 [j,end)，使其升序
     * 如果在步骤 1 找不到符合的相邻元素对，说明当前 [begin,end) 为一个降序顺序，则直接跳到步骤 4
     *
     *
     * 下一个数 比当前数大
     * 1.将后面的「大数」与前面的「小数」交换
     * 2.增加的幅度尽可能的小   尽可能小的「大数」 与前面的「小数」交换
     * 3.将「大数」换到前面后，需要将「大数」后面的所有数 重置为升序，升序排列就是最小的排列
     * @param nums
     */
    public static void handle(int[] nums) {
        int index = -1;
        int cur = -1;
        for (int i = nums.length-1; i >=0 ; i--) {
            int num0 = nums[i];
            for (int j = i-1; j >=0; j--) {
                if (nums[j]<num0 && j>index) {
                    index = j;
                    cur = i;
                    break;
                }
            }
        }
        if (index == -1) {
            Arrays.sort(nums);
        } else {
            swap(cur ,index, nums);
            sort(index+1, nums);
        }
    }

    private static void sort(int i, int[] nums) {
        for (int j = i; j < nums.length-1; j++) {
            for (int k = j+1; k < nums.length; k++) {
                if (nums[j]>nums[k]) {
                    swap(j, k, nums);
                }
            }
        }
    }

    private static void swap(int cur, int index, int[] nums) {
        int temp = nums[cur];
        nums[cur] = nums[index];
        nums[index] = temp;
    }

    private static void printArr(int[] arr) {
        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i] + " ");
        }
        System.out.println("");
    }

    public static void nextPermutation(int[] nums) {
        int i = nums.length - 2;
        while (i>=0 && nums[i]>=nums[i+1]) {
            i--;
        }
        if (i >= 0) {
            int j = nums.length - 1;
            while (j>=0 && nums[i]>=nums[j]) {
                j--;
            }
            swap(i, j, nums);
        }
        reserve(i+1, nums);
    }

    private static void reserve(int index, int[] nums) {
        int start = index, end = nums.length-1;
        while (start<end){
            swap(start, end, nums);
            start++;
            end--;
        }
    }

}
